package utils;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;


/**
 * FTP 上传工具类
 *
 * @author xuzhongliang
 * @date 2015年6月10日
 */

public class FtpUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(FtpUtil.class);

    private FTPClient ftp;

    /**
     * @param path     上传到ftp服务器哪个路径下
     * @param addr     地址
     * @param port     端口号
     * @param username 用户名
     * @param password 密码
     * @return 成功 失败
     * @throws Exception
     */
    public boolean connect(String path, String addr, String port, String username, String password) throws Exception {
        boolean result = false;
        ftp = new FTPClient();
        ftp.setControlEncoding("GBK");  //设置编码
        int reply;
        ftp.connect(addr, Integer.parseInt(port));
        ftp.login(username, password);
        ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
        ftp.enterLocalPassiveMode();
        reply = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            LOGGER.error("FTP连接失败    path：" + path + ",addr：" + addr + ",port:" + port + ",username:" + username + ",password:" + password);
            return result;
        }
        //result=ftp.changeWorkingDirectory(path);
        //if(!result)  LOGGER.error("FTP设置工作目录失败： "+path);
        result = ftp.changeWorkingDirectory(path);
        if (!result) {
            LOGGER.info("目录不存在，创建目录：" + path);
            ftp.makeDirectory(path);
            result = ftp.changeWorkingDirectory(path);
            if (!result) LOGGER.error("FTP设置工作目录失败：" + path);
        }
        return result;
    }

    /**
     * @param path ftp上文件路径
     * @param out  输出流
     * @throws Exception
     * @author jstian1
     */
    public boolean download(String path, FileOutputStream out) throws Exception {
        boolean temp = false;
        temp = ftp.retrieveFile(path, out);
        return temp;
    }

    /**
     * @param path       ftp中源文件路径
     * @param renamePath ftp中目标文件路径
     * @throws Exception
     * @author jstian1
     */
    public boolean renameFile(String path, String renamePath) throws Exception {
        boolean temp = false;
        temp = ftp.rename(path, renamePath);
        return temp;
    }

    /**
     * @param path 获取文件列表的目录
     * @throws Exception
     * @author jstian1
     */
    public FTPFile[] getFtpFiles(String path) throws Exception {
        FTPFile[] ftpFiles = ftp.listFiles(path);
        return ftpFiles;
    }

    /**
     * @param path 新建文件夹名
     * @return
     * @throws Exception
     */
    public boolean makeDir(String path) throws Exception {
        boolean temp = false;
        temp = ftp.makeDirectory(path);
        return temp;
    }

    /**
     * @param file 上传的文件或文件夹
     * @throws Exception
     */
    public boolean upload(File file) throws Exception {
        boolean temp = false;
        if (file.isDirectory()) {
            ftp.makeDirectory(file.getName());
            temp = ftp.changeWorkingDirectory(file.getName());
            if (!temp) {
                LOGGER.error("FTP 设置工作目录失败" + file.getName());
                return false;
            }
            String[] files = file.list();
            for (int i = 0; i < files.length; i++) {
                File file1 = new File(file.getPath() + "\\" + files[i]);
                if (file1.isDirectory()) {
                    upload(file1);
                    temp = ftp.changeToParentDirectory();
                    if (!temp) {
                        LOGGER.error("FTP 返回父级工作目录失败" + file1.getName());
                        return false;
                    }
                } else {
                    File file2 = new File(file.getPath() + "\\" + files[i]);
                    FileInputStream input = new FileInputStream(file2);
                    temp = ftp.storeFile(file2.getName(), input);
                    input.close();
                    if (!temp) {
                        LOGGER.error("FTP 上传文件失败" + file2.getName());
                        return false;
                    }
                }
            }
        } else {
            File file2 = new File(file.getPath());
            FileInputStream input = new FileInputStream(file2);
            temp = ftp.storeFile(file2.getName(), input);
            if (!temp) {
                LOGGER.error("FTP 上传文件失败" + file2.getName());
                return false;
            }
            input.close();
        }
        return true;
    }

    /**
     * 断开FTP
     */
    public void logout() {
        try {
            if (this.ftp != null) {
                this.ftp.logout();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {

//        Path path = Paths.get("D:", "33.txt");


        Path tempFile = Files.createTempFile("", ".tmp");
        Files.write(tempFile, "".getBytes(StandardCharsets.UTF_8));
//        String join = String.join("a", "sadf", "sdfa", "sdf");
//        System.out.println(join);

        FtpUtil t = new FtpUtil();
        boolean temp = t.connect("/umsapp/dc/am/ddl", "144.131.254.138", "21", "dc", "datacenter_2016");
        if (temp) {
            t.upload(tempFile.toFile());
            t.renameFile(tempFile.getFileName().toString(), "Enum.txt");
        }
        t.logout();
        //System.out.println(FileUtils.getMd5ByFile(file1));
    }


    public boolean makeDirectories(FTPClient ftpClient, String dirPath) throws IOException {
        if (ftpClient == null) {
            LOGGER.error("FTPClient为空");
            return false;
        }
        if (Strings.isNullOrEmpty(dirPath)) {
            LOGGER.error("要创建的目录为空");
            return false;
        }
        boolean startWithRoot = false;
        if (dirPath.startsWith("/")) {
            startWithRoot = true;
        }
        String[] pathElements = dirPath.split("/");
        if (pathElements != null && pathElements.length > 0) {
            String singleDir = "";
            for (int i = 0; i < pathElements.length; i++) {
                singleDir = pathElements[i];
                if (Strings.isNullOrEmpty(singleDir)) {
                    continue;
                }
                if (startWithRoot && i == 1) {
                    singleDir = "/" + singleDir;
                }

                boolean existed = ftpClient.changeWorkingDirectory(singleDir);
                if (!existed) {
                    boolean created = ftpClient.makeDirectory(singleDir);
                    if (created) {
                        System.out.println(ftpClient.printWorkingDirectory());
                        ftpClient.changeWorkingDirectory(singleDir);
                        System.out.println(ftpClient.printWorkingDirectory());
                    } else {
                        return false;
                    }
                } else {
                    System.out.println(ftpClient.printWorkingDirectory());
                }
            }
        }
        return true;
    }

    public boolean connectFtp(String path, String addr, String port, String username, String password) throws Exception {
        boolean result = false;
        ftp = new FTPClient();
        ftp.setControlEncoding("GBK");  //设置编码
        int reply;
        ftp.connect(addr, Integer.parseInt(port));
        ftp.login(username, password);
        ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
        ftp.enterLocalPassiveMode();
        reply = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            LOGGER.error("FTP连接失败    path：" + path + ",addr：" + addr + ",port:" + port + ",username:" + username + ",password:" + password);
            return result;
        }
        System.out.println(ftp.printWorkingDirectory());
        result = ftp.changeWorkingDirectory(path);
        if (!result) {
            LOGGER.info("目录不存在，创建目录：" + path);
            boolean created = makeDirectories(ftp, path);
            result = ftp.changeWorkingDirectory(path);
            if (!result) LOGGER.error("FTP设置工作目录失败：" + path);
        }
        return result;
    }

    //判断文件是否存在，文件所处的路径为FTPClient ftp所处的路径，sourceFileName只包含文件名，未包含路径
    public boolean isFileExist(String sourceFileName) {
        boolean existed = false;
        try {
            Preconditions.checkNotNull(ftp, "FTP连接为空");
            Preconditions.checkState(!Strings.isNullOrEmpty(sourceFileName), "原文件名为空");
            FTPFile[] ftpFiles = ftp.listFiles(sourceFileName);
            if (ftpFiles == null || ftpFiles.length <= 0) {
                LOGGER.info("指定位置上不存在文件：{}", sourceFileName);
                existed = false;
            } else {
                LOGGER.info("指定位置上存在文件：{}", sourceFileName);
                existed = true;
            }
        } catch (Exception ex) {
            LOGGER.error("判断文件是否存在失败：" + ex.getMessage(), ex);
            existed = false;
        }
        return existed;
    }

    //更改文件名，sourceFileName,destFileName均只有文件名，未包括路径，路径已经通过FTPClient体现
    public boolean changeFileName(String sourceFileName, String destFileName) {
        boolean changed = false;
        try {
            Preconditions.checkNotNull(ftp, "FTP连接为空");
            Preconditions.checkState(!Strings.isNullOrEmpty(sourceFileName), "源文件名为空");
            Preconditions.checkState(!Strings.isNullOrEmpty(destFileName), "目标文件名为空");
            FTPFile[] ftpFiles = ftp.listFiles(sourceFileName);
            Preconditions.checkState(!(ftpFiles == null || ftpFiles.length <= 0), "指定路径上不存在和源文件相同的文件");
            ftpFiles = ftp.listFiles(destFileName);
            Preconditions.checkState(!(ftpFiles.length > 0), "指定路径上已经存在和目标文件相同的文件");
            changed = ftp.rename(sourceFileName, destFileName);
        } catch (Exception ex) {
            LOGGER.error("更改文件名失败:" + ex.getMessage(), ex);
            changed = false;
        }
        return changed;
    }

    public FTPClient getFtp() {
        return ftp;
    }
    
	public void createPath(String allPath){
		if(null != ftp){
			try {
				ftp.makeDirectory(allPath);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void changePath(String path){
		if(null != ftp){
			try {
				ftp.changeWorkingDirectory(path);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
